package org.dyndns.opendemogroup.optimizer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * A convenience class to compensate for the "enterpriseness" of the <i>"Java
 * API for XML Processing."</i>
 */
public class Xml
{

	private static XPath xpath = XPathFactory.newInstance ( ).newXPath ( );

	public static Node selectSingleNode ( final Element node,
			final String expression )
	{
		Node result = null;
		xpath.reset ( );
		try
		{
			result =
				(Node) xpath.evaluate ( expression, node, XPathConstants.NODE );
		}
		catch ( XPathExpressionException e )
		{
			assert false : "XPathExpressionException";
			e.printStackTrace ( );
		}
		return result;
	}

	public static NodeList selectNodes ( final Element node,
			final String expression )
	{
		NodeList result = null;
		xpath.reset ( );
		try
		{
			result =
				(NodeList) xpath.evaluate ( expression, node,
					XPathConstants.NODESET );
		}
		catch ( XPathExpressionException e )
		{
			assert false : "XPathExpressionException";
			e.printStackTrace ( );
		}
		return result;
	}

	/**
	 * A convenience method to get around the "enterpriseness" of the <i>"Java
	 * API for XML Processing."</i>
	 * 
	 * @param xml
	 *        A string representing some XML to load.
	 * @return A {@link Document} representing the XML content in <i>xml</i>.
	 */
	public static Document loadDocument ( final String xml )
	{
		Document result = null;
		try
		{
			final DocumentBuilderFactory factory =
				DocumentBuilderFactory.newInstance ( );
			final DocumentBuilder builder = factory.newDocumentBuilder ( );
			final ByteArrayInputStream bais =
				new ByteArrayInputStream ( xml.getBytes ( ) );
			result = builder.parse ( bais );
		}
		catch ( SAXException e )
		{
			assert false : "SAXException";
			e.printStackTrace ( );
		}
		catch ( IOException e )
		{
			assert false : "IOException";
			e.printStackTrace ( );
		}
		catch ( ParserConfigurationException e )
		{
			assert false : "ParserConfigurationException";
			e.printStackTrace ( );
		}
		return result;
	}

	public static String saveDocument ( Document doc )
	{
		TransformerFactory tf = TransformerFactory.newInstance ( );

		String result = null;
		try
		{
			Transformer t;
			ByteArrayOutputStream baos = new ByteArrayOutputStream ( 1000 );
			t = tf.newTransformer ( );
			t.transform ( new DOMSource ( doc ), new StreamResult ( baos ) );
			result = baos.toString ( );
		}
		catch ( TransformerConfigurationException e )
		{
			assert false : "TransformerConfigurationException";
			e.printStackTrace ( );
		}
		catch ( TransformerException e )
		{
			assert false : "TransformerException";
			e.printStackTrace ( );
		}
		return result;
	}
}
